using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Functional
{
    public class Maps
    {
        public static T[] Map<T>(int totalGenerations) where T: new()
        {
            Int32 L;
            T[] lOut = new T[totalGenerations];
            for (L = 0; L < totalGenerations; L++)
            {
                lOut[L] = new T();
            }
            return lOut;
        }

        public static T[] Map<T>(int totalGenerations, Func<T> generationFunction)
        {
            Int32 L;
            T[] lOut = new T[totalGenerations];
            for (L = 0; L < totalGenerations; L++)
            {
                lOut[L] = generationFunction();
            }
            return lOut;
        }

        public static T2[] Map<T1, T2>(T1 in1, int totalGenerations, Func<T1, T2> generationFunction)
        {
            Int32 L;
            T2[] lOut = new T2[totalGenerations];
            for (L = 0; L < totalGenerations; L++)
            {
                lOut[L] = generationFunction(in1);
            }
            return lOut;
        }

        public static T3[] Map<T1,T2,T3>(T1 in1,T2 in2,int totalGenerations,Func<T1,T2,T3> generationFunction)
        {
            Int32 L;
            T3[] lOut = new T3[totalGenerations];
            for (L = 0; L < totalGenerations; L++)
            {
                lOut[L] = generationFunction(in1,in2);
            }
            return lOut;
        }

        public static T[] Map<T>(T input)
        {
            T[] lOut = new T[1];
            lOut[0] = input;
            return lOut;
        }

        public static T[] Map<T>(T[] inputs)
        {
            T[] lOut = new T[inputs.Length];
            inputs.CopyTo(lOut, 0);
            return lOut;
        }

        public static TOut[] Map<TIn, TOut>(TIn[] inputs, Func<TIn, TOut> mapFunction)
        {
            Int32 L;
            TOut[] lOut = new TOut[inputs.Length];
            for (L = 0; L < inputs.Length; L++)
            {
                lOut[L] = mapFunction(inputs[L]);
            }
            return lOut;
        }

        public static TOut[] Map<TIn1, TIn2, TOut>(TIn1[] inputs, TIn2 input, Func<TIn1, TIn2, TOut> mapFunction)
        {
            Int32 L;
            TOut[] lOut = new TOut[inputs.Length];
            for (L = 0; L < inputs.Length; L++)
            {
                lOut[L] = mapFunction(inputs[L], input);
            }
            return lOut;
        }

        public static TOut[] Map<TIn1, TIn2, TOut>(TIn1[] inputs1, TIn2[] inputs2, Func<TIn1, TIn2, TOut> mapFunction)
        {
            Int32 L;
            TOut[] lOut = new TOut[inputs1.Length];
            for (L = 0; L < inputs1.Length; L++)
            {
                lOut[L] = mapFunction(inputs1[L], inputs2[L]);
            }
            return lOut;
        }


        public static TOut[] MapTwoArrays<TIn1, TIn2, TOut>(TIn1[] inputs1, TIn2[] inputs2, Func<TIn1, TIn2, TOut> mapFunction)
        {
            Int32 L;
            TOut[] lOut = new TOut[inputs1.Length];
            for (L = 0; L < inputs1.Length; L++)
            {
                lOut[L] = mapFunction(inputs1[L], inputs2[L]);
            }
            return lOut;
        }

        //public static T2[] ParallelMap<T1, T2>(T1[] inArray, Func<T1, T2> function)
        //{
        //    T2[] lOut = new T2[inArray.Length];
        //    T2 TOut;
        //    Parallel.For(0, inArray.Length, i =>
        //    {
        //        TOut = function(inArray[i]);
        //        lOut[i] = TOut;
        //    });
        //    return lOut;
        //}

        //public static TOut[] ParallelMap<TIn1, TIn2, TOut>(TIn1[] inputs, TIn2 input, Func<TIn1, TIn2, TOut> mapFunction)
        //{
        //    TOut[] lOut = new TOut[inputs.Length];
        //    Parallel.For(0, inputs.Length, L =>
        //    {
        //        lOut[L] = mapFunction(inputs[L], input);
        //    });
        //    return lOut;
        //}

        //public static TOut[] ParallelMap<TIn1, TIn2, TOut>(TIn1[] inputs1, TIn2[] inputs2, Func<TIn1, TIn2, TOut> mapFunction)
        //{
        //    TOut[] lOut = new TOut[inputs1.Length];
        //    Parallel.For(0, inputs1.Length, L =>
        //    {
        //        lOut[L] = mapFunction(inputs1[L], inputs2[L]);
        //    });
        //    return lOut;
        //}








        //List maps!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


        public static List<T2> Map<T1, T2>(List<T1> inList, Func<T1, T2> function)
        {
            List<T2> lOut = new List<T2>();
            T2 TOut;
            foreach (T1 t in inList)
            {
                TOut = function(t);
                lOut.Add(TOut);
            }
            return lOut;
        }

        public static List<T3> Map<T1, T2, T3>(List<T1> inList1, T2 t, Func<T1, T2, T3> function)
        {
            List<T3> lOut = new List<T3>();
            T3 TOut;
            Int32 L;
            for (L = 0; L < inList1.Count; L++)
            {
                TOut = function(inList1[L], t);
                lOut.Add(TOut);
            }
            return lOut;
        }

        public static List<T3> Map<T1, T2, T3>(List<T1> inList1, List<T2> inList2, Func<T1, T2, T3> function)
        {
            List<T3> lOut = new List<T3>();
            T3 TOut;
            Int32 L;
            for (L = 0; L < inList1.Count; L++)
            {
                TOut = function(inList1[L], inList2[L]);
                lOut.Add(TOut);
            }
            return lOut;
        }

        public static List<T3> MapTwoArrays<T1, T2, T3>(List<T1> inList1, List<T2> inList2, Func<T1, T2, T3> function)
        {
            List<T3> lOut = new List<T3>();
            T3 TOut;
            Int32 L;
            for (L = 0; L < inList1.Count; L++)
            {
                TOut = function(inList1[L], inList2[L]);
                lOut.Add(TOut);
            }
            return lOut;
        }

        //public static List<T> Map<T>(int totalGenerations) where T:new()
        //{
        //    Int32 L;
        //    List<T> lOut = new List<T>();
        //    for (L = 0; L < totalGenerations; L++)
        //    {
        //        lOut.Add(new T());
        //    }
        //    return lOut;
        //}

    }
}